﻿using System;
using System.Threading;

namespace vm.Aspects.Threading
{
    public sealed class ReaderSlimSync : IDisposable
    {
        ReaderWriterLockSlim _readerWriterLock;

        /// <summary>
        /// Initializes a new instance of the <see cref="UpgradeableReaderSlimSync"/> class with the specified <paramref name="readerWriterLock"/> and
        /// waits indefinitely till it acquires the lock in reader mode.
        /// </summary>
        /// <param name="readerWriterLock">The reader writer lock.</param>
        public ReaderSlimSync(
            ReaderWriterLockSlim readerWriterLock)
        {
            if (readerWriterLock == null)
                throw new ArgumentNullException("readerWriterLock");

            readerWriterLock.EnterReadLock();
            _readerWriterLock = readerWriterLock;
        }

        #region IDisposable pattern implementation
        /// <summary>
        /// The flag is being set when the object gets disposed.
        /// </summary>
        /// <value>
        /// 0 - if the object is not disposed yet, any other value would mean that the object is already disposed.
        /// </value>
        int _disposed;

        /// <summary>
        /// Returns <see langword="true"/> if the object has already been disposed, otherwise <see langword="false"/>.
        /// </summary>
        public bool IsDisposed
        {
#if DOTNET_4_0
            get { return _disposed != 0; }
#else
            get { return Volatile.Read(ref _disposed) != 0; }
#endif
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (Interlocked.Exchange(ref _disposed, 1) == 0)
                _readerWriterLock.ExitReadLock();
        }
        #endregion
    }
}
